/*
 * Created on April 29, 2005
 *
 * Copyright (c) Patrick Armstrong 2002-2007. All Rights Reserved
 */
package org.dime.mine.bot;

import java.util.List;

import org.dime.mine.bot.AwareBoard.AwareLocation;
import org.dime.mine.game.Board;
import org.dime.mine.game.actions.Action;
import org.dime.mine.game.actions.Mark;
import org.dime.mine.game.actions.None;
import org.dime.mine.game.actions.Open;
import org.dime.mine.game.actions.Unmark;

/**
 * Exhaustion is a solution algorithm. It tries to check all possible board
 * configurations. If there is a location that has the same value across all
 * valid boards then that the value for that location must be the true value.
 * 
 * @author Owner
 */
public class Exhaustion extends AbstractStrategy
{
    @Override
    public boolean execute(Board board)
    {
        // TODO reorder list of UnsolvedLocations to prioritize unsolved
        // locations with fewer mine configurations
        AwareBoard awareBoard = new AwareBoard(board);
        for (AwareLocation location : awareBoard.getUnsolvedLocations())
        {
            if (executeHelper(board, location))
                return true;
        }
        return false;
    }

    @Override
    public boolean execute(Board board, int row, int column)
    {
        // TODO add this method or something similar to other strategies and
        // possibly sub-interface of Strategy
        return executeHelper(board, new AwareBoard(board).getAwareLocation(row,
                column));
    }

    private boolean executeHelper(Board board, AwareBoard.AwareLocation location)
    {
        boolean flag = false;
        List<TestBoard> possibles = new Investigation(board, location)
                .getValidOutcomes();

        Action action;
        for (int i = 0; i < board.getRows(); i++)
        {
            for (int j = 0; j < board.getColumns(); j++)
            {
                action = getAction(board, possibles, board.getLocation(i, j));
                if (!(action instanceof None))
                {
                    action.execute();
                    flag = true;
                }
            }
        }

        return flag;
    }

    private Action getAction(Board board, List<TestBoard> outcomes,
            Board.Location location)
    {
        Integer value = getSharedValue(outcomes, location.getRow(), location
                .getColumn());
        if (value == null || value.intValue() == location.getValue())
            return new None(location);
        else if (value.intValue() == Board.MARKED)
            return new Mark(location);
        else if (value.intValue() == Board.NOT_OPEN)
            return new Unmark(location);
        else
            return new Open(location);
    }

    private Integer getSharedValue(List<TestBoard> outcomes, int row, int column)
    {
        Integer value = null;
        for (int index = 0; index < outcomes.size(); index++)
        {
            if (value == null)
                value = new Integer(outcomes.get(index).check(row, column));
            else if (outcomes.get(index).check(row, column) != value.intValue())
            {
                value = null;
                break;
            }
        }
        return value;
    }
}